#include "ax_fork.h"
#include "ax_printf.h"
#include "com.h"

#include <stdbool.h>
#include <sys/types.h>
#include <linux/wait.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>



struct ax_fork
{
    ax_fork_cb cb;
    void*      param;
    int        child_pid;
};

ax_fork* ax_fork_create()
{
    ax_fork* f = ALLOC(ax_fork);
    f->cb      = NULL;
    return f;
}

void ax_fork_destroy(ax_fork* f)
{
    if(f)
    {
        FREE(f);
    }
}

/**
 * @brief fork a new process and pass cb
 * @param f
 * @param cb     func to new process
 * @param param  param to new process
 * @return true when ok in local process
 */
bool ax_fork_run(ax_fork* f, ax_fork_cb cb, void* param)
{
    f->cb   = cb;
    int pid = fork();
    if(pid < 0)
    {
        return false;
    }
    else if(pid == 0)
    {
        /* new process */
        exit(cb(param));
        return true;
    }
    else
    {
        /* local process */
        f->child_pid = pid;
        ax_info("fork new. child_pid:%d mypid:%d\n", f->child_pid, getpid());
        return true;
    }
}

/**
 * @brief wait until process exit, and get exit code
 * @param f
 * @return exit code of process
 */
int ax_fork_wait(ax_fork* f)
{
    int      status    = -1;
    unsigned exit_code = 0;
    int      ret       = waitpid(f->child_pid, &status, WUNTRACED);  // will return pid
    exit_code          = WEXITSTATUS(status);
    ax_info("mypid:%d child_pid:%d exit code:%d waitpid ret:%d\n", getpid(), f->child_pid, exit_code & 0xFF, ret);
    return exit_code;
}

/**
 * @brief ax_fork_kill
 * @param f
 * if killed, new process return 0
 */
void ax_fork_kill(ax_fork* f)
{
    if(f == 0 || f->child_pid == 0)
        return;
    if(0 ==kill(f->child_pid, SIGKILL))
    {
        ax_info("kill %d ok!\n", f->child_pid);
    }
    else
    {
        ax_error("kill %d fail!\n", f->child_pid);
    }
}
